#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "hv/hv.h"

#include "hv/hlog.h"
#include "callback.h"
#include "socks5.h"
#include "optparser.h"
#include "help.h"

#define EPOLL_SIZE 1024
#define LISTEN_BACKLOG 128
#define MAX_EVENTS_COUNT 128
#define LISTEN_PORT 1080

static void signal_handler(int sig) {
    logger_info("receive signal: [%d]\n", sig);

    switch (sig) {
        case SIGINT:
        case SIGTERM:
            break;
        default:
            logger_warn("unknown signal [%d]\n", sig);
    }
}

static int register_signals() {
    // ctrl + c
    if (SIG_ERR == signal(SIGINT, signal_handler)) {
        logger_error("register signal SIGINT fail\n");
        return -1;
    }

    // pkill
    if (SIG_ERR == signal(SIGTERM, signal_handler)) {
        logger_error("register signal SIGTERM fail\n");
        return -1;
    }

    return 0;
}

struct socks5_server g_server = {
    0,
    "",
    0,
    "",
    LISTEN_PORT,
    SOCKS5_AUTH_NOAUTH,
    false,
};

int main (int argc, char **argv) {
	signal(SIGPIPE, SIG_IGN);
    if (socks5_server_parse(argc, argv) < 0) {
        help(argv[0]);
        exit(EXIT_FAILURE);
    }

    hlog_set_file("/tmp/socks5");
    hlog_set_level_by_str("DEBUG");
    hlog_set_max_filesize_by_str("10M");

    if (g_server.daemon) {
        if (daemon(1, 0) < 0) {
            LOGE("daemon fail, errno [%d]\n", errno);
            exit(EXIT_FAILURE);
        }
    }

    LOGI("starting ...\n");

    hloop_t *loop = hloop_new(0);


    // if (register_signals() < 0) {
    //     logger_error("register_signals fail, errno: [%d]\n", errno);
    //     exit(EXIT_FAILURE);
    // }
	hio_t* listenio = hloop_create_tcp_server(loop, "0.0.0.0", g_server.port, on_accept);
	if (listenio == NULL) {
		return -20;
	}
	hloop_set_userdata(loop, &g_server);

    LOGI("start working, port: [%d], auth_method: [%d]\n", g_server.port, g_server.auth_method);
    hloop_run(loop);

    LOGI("exiting ...\n");

    hloop_free(&loop);

    return EXIT_SUCCESS;
}
